package com.longcai.cm.pay.wx;

import com.longcai.cm.exception.SysRuntimeException;
import com.wechat.pay.java.core.notification.RequestParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
 * @author libingxing
 */
public class WXPayUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(WXPayUtil.class);

    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();

    public static RequestParam getRequestParam(HttpServletRequest request) {
        final String serial = request.getHeader("Wechatpay-Serial");
        LOGGER.info(serial);
        final String nonce = request.getHeader("Wechatpay-Nonce");
        LOGGER.info(nonce);
        final String signature = request.getHeader("Wechatpay-Signature");
        LOGGER.info(signature);
        final String timestamp = request.getHeader("Wechatpay-Timestamp");
        LOGGER.info(timestamp);
        final String requestBody = WXPayUtil.getRequestBody(request);
        LOGGER.info(requestBody);

        return new RequestParam.Builder()
                //证书序列号（微信平台）
                .serialNumber(serial)
                //随机串
                .nonce(nonce)
                //微信传递过来的签名
                .signature(signature)
                //时间戳
                .timestamp(timestamp)
                //获取报文
                .body(requestBody)
                .build();
    }

    public static String getPreSignApp(Map<String, String> param) {
        return getPreSign(param, 1);
    }

    public static String getPreSignMicro(Map<String, String> param) {
        return getPreSign(param, 2);
    }

    public static String getPreSign(Map<String, String> param, Integer type) {
        final StringBuilder builder = new StringBuilder();
        final Set<Map.Entry<String, String>> entrySet = param.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            builder.append(entry.getValue()).append("\n");
        }
        return signBySHA256WithRSA(builder.toString(), type);
    }

    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    /**
     * 获取私钥。
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {

        String content = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

    /**
     * SHA256withRSA签名
     *
     * @param content 加密内容
     * @author xpl
     */
    public static String signBySHA256WithRSA(String content, Integer type) {
        try {
            PrivateKey priKey = getPrivateKey(WxPayConstants.PRIVATE_KEY_APP);

            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(priKey);
            signature.update(content.getBytes(StandardCharsets.UTF_8));

            return org.apache.commons.codec.binary.Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            //签名失败
            return null;
        }
    }

    /**
     * 读取请求数据流
     */
    public static String getRequestBody(HttpServletRequest request) {

        StringBuilder sb = new StringBuilder();

        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException ignored) {
        }

        return sb.toString();

    }

    public static String convertRefundStatus(String status) {
        switch (status) {
            case "SUCCESS":
                return "";
            case "CLOSED":
                return "退款关闭";
            case "PROCESSING":
                return "退款处理中";
            case "ABNORMAL":
                return "退款异常";
            default:
                return "退款遇到未知异常，请联系平台进行处理";
        }
    }

}
